//
//  WLImageSequenceView.swift
//  WLVehicleConfiguration
//
//  Created by dowZhang on 2017/9/26.
//  Copyright © 2017年 Yongpeng.Zhu. All rights reserved.
//

import UIKit
import Kingfisher

protocol WLImageSequenceViewDelegate: NSObjectProtocol {
    func imageSequenceViewSwipe(translation: CGPoint, index: Int)
}

class WLImageSequenceView: UIView {
    
    weak var delegate: WLImageSequenceViewDelegate?
    
    /**
     * Sensitivity of image sequence rotation
     
     * Higher sensitivity means slower rotation
     
     * The default value is 0.8
     */
    var sensivity: CGFloat!
    /**
     * Posibility of image zoom
     
     * You can't rotate image, if zoom scale is more then 1.0 (normal image size)
     
     * The default value is FALSE
     */
    var zoomEnabled: Bool!
    /**
     * Posibility of image zoom bounces
     
     * The default value is FALSE
     */
    var zoomBouncesEnabled: Bool!
    
    /**
     * Maximum scale factor for zooming. It must be greater than the minimum zoom scale for zooming to be enabled.
     
     * This value determines how large the content can be scaled.
     
     * The default value is 1.0.
     
     */
    var maximumZoomScale: CGFloat!
    
    /**
     * Minimum scale factor for zooming.
     
     * This value determines how small the content can be scaled.
     
     * This property is readonly and the value is always 1.0. It needs for correct working of image sequence mechanics.
     
     */
    var minimumZoomScale: CGFloat!
    
    /**
     * Turning on / off  inertia on image rotating
     
     * If this property is true, image will continue rotating for some time with deceleration
     after you end rotating gesture (similarly as scrolling of UITableView)
     
     * The default value is FALSE
     */
    var inertiaEnabled: Bool!
    
    /**
     * Content mode of image
     
     * The default value is UIViewContentModeScaleAspectFit
     */
    var imageContentMode: UIView.ContentMode!
    
    lazy var imageView: UIImageView = {
        let imageView = UIImageView.init(frame: CGRect.init(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height))
        imageView.contentMode = UIView.ContentMode.scaleAspectFit
        imageView.isUserInteractionEnabled = true
        return imageView
    }()
    
    lazy var scrollView: UIScrollView = {
        let scrollView = UIScrollView.init(frame: CGRect.init(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height))
        scrollView.isScrollEnabled = false
        scrollView.delegate = self
        scrollView.bounces = false
        scrollView.bouncesZoom = self.zoomBouncesEnabled
        scrollView.minimumZoomScale = self.minimumZoomScale
        scrollView.maximumZoomScale = self.maximumZoomScale
        scrollView.showsVerticalScrollIndicator = false
        scrollView.showsHorizontalScrollIndicator = false
        return scrollView
    }()
    
    var imagesArray = [UIImage]() {
        didSet {
            if imagesArray.count > 0 {
                setupDefaultValue(images: imagesArray)
            }
        }
    }
    
    var imagesUrls = [String]() {
        didSet {
            if imagesUrls.count > 0 {
                setupDefaultValueUrl(imageUrls: imagesUrls)
            }
        }
    }
    
    var currentIndex: Int = 0
    
    //MARK:cycle life
    convenience init(images: [UIImage], frame: CGRect) {
        self.init(frame: frame)
        self.backgroundColor = .white
        imagesArray = images
    }
    
    private override init(frame: CGRect) {
        
        //Default values
        
        self.sensivity = 1.8
        self.zoomEnabled = false
        self.zoomBouncesEnabled = false
        self.maximumZoomScale = 1.0
        self.minimumZoomScale = 1.0
        self.inertiaEnabled = true
        
        super.init(frame: frame)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    //MARK:private method
    private func setupDefaultValue(images: [UIImage]) {
        currentIndex = currentIndex % 36
        
        imageView.image = imagesArray[currentIndex]
        self.addSubview(scrollView)
        let panGesture = UIPanGestureRecognizer.init(target: self, action: #selector(handleSwipe(swipe:)))
        imageView.addGestureRecognizer(panGesture)
        
        scrollView.addSubview(imageView)
    }
    
    
    //YongPeng Fixed
    private func setupDefaultValueUrl(imageUrls: [String]) {
        currentIndex = currentIndex % 36
        let imageStr = imagesUrls[currentIndex]
        if let imgUrl = URL(string: imageStr) {
            imageView.kf.setImage(with: imgUrl,options: [.onlyFromCache])
            self.addSubview(scrollView)
            let panGesture = UIPanGestureRecognizer.init(target: self, action: #selector(handleSwipe(swipe:)))
            imageView.addGestureRecognizer(panGesture)
            scrollView.addSubview(imageView)
        }
    }
    
    
    /// right -> left swipe
    func setNext() {
        currentIndex = (currentIndex + 1) % imagesArray.count
        imageView.image = imagesArray[currentIndex]
    }
    
    /// left -> right swipe
    func setPrevious() {
        currentIndex = (currentIndex + imagesArray.count - 1) % imagesArray.count
        imageView.image = imagesArray[currentIndex]
    }
    
    /// to origin point by Yongpeng
    func gobackOrigin(rotateSpeed: Double = 0.015, completion finish: @escaping ()->()) {
        if Float(self.imagesArray.count - self.currentIndex) > Float(self.imagesArray.count/2) {
            //left -> right
            self.onTickPreviousUntilOrigin(moveSpeed: rotateSpeed, completion: finish)
        } else {
            //right -> left
            self.onTickNextUntilOrigin(moveSpeed: rotateSpeed, completion:  finish)
        }
    }
    
    //MARK: goback original point
    private func onTickNextUntilOrigin(moveSpeed: Double, completion: @escaping ()->()) { //越来越小
        DispatchQueue.main.asyncAfter(deadline: .now() + moveSpeed) {
            guard self.currentIndex != 0,
                (self.currentIndex >= 0 && (self.currentIndex < self.imagesArray.count)) else {
                    completion()
                    return //exit
            }
            self.setNext()
            self.onTickNextUntilOrigin(moveSpeed: moveSpeed, completion: completion)
        }
    }
    
    private func onTickPreviousUntilOrigin(moveSpeed: Double, completion: @escaping ()->()) { //越来越大
        DispatchQueue.main.asyncAfter(deadline: .now() + moveSpeed) {
            guard self.currentIndex != 0,
                (self.currentIndex >= 0 && (self.currentIndex) < self.imagesArray.count) else {
                    completion()
                    return //exit
            }
            self.setPrevious()
            self.onTickPreviousUntilOrigin(moveSpeed: moveSpeed, completion: completion)
        }
    }
    
    
    
    //MARK: inertia
    private func onTickNextWithRemaningX(coordinateX: CGFloat) {
        self.setNext()
        if ((1-((coordinateX-10*self.sensivity)/coordinateX)) < 0.03) {
            let time = DispatchTime.now() + Double(1-((coordinateX-10*self.sensivity)/coordinateX))
            
            DispatchQueue.main.asyncAfter(deadline: time, execute: {
                self.onTickNextWithRemaningX(coordinateX: (coordinateX - 10*self.sensivity))
            })
        }
    }
    private func onTickPrevWithRemaningX(coordinateX: CGFloat) {
        self.setPrevious()
        if ((1-((coordinateX-10*self.sensivity)/coordinateX)) < 0.03) {
            let time = DispatchTime.now() + Double(1-((coordinateX-10*self.sensivity)/coordinateX))
            DispatchQueue.main.asyncAfter(deadline: time, execute: {
                self.onTickPrevWithRemaningX(coordinateX: (coordinateX - 10*self.sensivity))
            })
        }
    }
    
    fileprivate func centerScrollViewContents() {
        let boundsSize = scrollView.bounds.size
        var contentsFrame = imageView.frame
        
        if (contentsFrame.size.width < boundsSize.width) {
            contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0
        } else {
            contentsFrame.origin.x = 0.0
        }
        
        if (contentsFrame.size.height < boundsSize.height) {
            contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0
        } else {
            contentsFrame.origin.y = 0.0
        }
        
        imageView.frame = contentsFrame
    }
    
    //MARK: event response
    @objc func handleSwipe(swipe: UIPanGestureRecognizer) {
        if self.scrollView.zoomScale > self.minimumZoomScale { return }
        
        //Main Thread Don't Invoke This Function
        if swipe.state == UIGestureRecognizer.State.began || swipe.state == UIGestureRecognizer.State.changed {
            let translation = swipe.translation(in: self.imageView)
            if fabs(translation.x / 10 * self.sensivity) > 1 {
                if translation.x < 0 {
                    self.setNext()
                }else {
                    self.setPrevious()
                }
                swipe.setTranslation(CGPoint.zero, in: self.imageView)
            }
        }
        

        //惯性旋转
        if swipe.state == UIGestureRecognizer.State.ended && self.inertiaEnabled {
            
            let velocity = swipe.velocity(in: self.imageView)
            let x = velocity.x / 2
            //惯性小于25 不动
            if x < -25 {
                self.onTickNextWithRemaningX(coordinateX: fabs(x))
            }else if x > 25 {
                self.onTickPrevWithRemaningX(coordinateX: fabs(x))
            }
        }
    }
}


extension WLImageSequenceView: UIScrollViewDelegate {
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return imageView
    }
    func scrollViewDidZoom(_ scrollView: UIScrollView) {
        self.centerScrollViewContents()
    }
}
